package com.like.banzipao.server.util.roomstate

import com.like.banzipao.server.db.DatabaseHelper
import com.like.banzipao.server.model.FriendType
import com.like.banzipao.server.model.PlayerState
import com.like.banzipao.server.model.Poker
import com.like.banzipao.server.model.PokerState
import com.like.banzipao.server.model.Room
import com.like.banzipao.server.model.User
import com.like.banzipao.server.model.pokerComparator
import com.like.banzipao.server.model.users
import com.like.banzipao.server.util.dealPokers
import org.ktorm.entity.update

/**
 * 准备阶段的一些方法实现
 */
class ReadyRoomState(room: Room, private val onReady: (BaoType) -> Unit) : BaseRoomState(room) {
    private var isDrawn = false// 是否换牌了

    // 喊牌时能喊的牌
    private val hanPokers = sortedSetOf(pokerComparator)

    override fun ready(user: User, dealerUserId: Int) {
        if (user.roomCard <= 0) {
            throw IllegalStateException("房卡不足，无法进行游戏！")
        }
        user.roomCard--
        if (DatabaseHelper.database.users.update(user) <= 0) {
            user.roomCard++
            throw IllegalStateException("服务器错误，无法更新房卡数量！")
        }
        for (player in room.players) {
            if (player?.user?.id == user.id) {
                player.user.roomCard = user.roomCard
                break
            }
        }

        val player = getPlayer(user) ?: return
        player.state = PlayerState.READY
        if (isFull() && isAllReady()) {
            room.players.forEach {
                it?.let {
                    // 从庄家开始爆牌
                    it.state = if (it.user.id == dealerUserId) {
                        PlayerState.BAO_TURN
                    } else {
                        PlayerState.BAOING
                    }
                }
            }
            room.pokers.clear()
            room.pokers.addAll(dealPokers(dealerUserId, room.players.mapNotNull { it }.toTypedArray()))

            val spade7HolderUserId = getSpade7()?.holderUserId
            hanPokers.clear()
            hanPokers.addAll(room.pokers.filter {
                it.holderUserId != spade7HolderUserId
            })
        }
    }

    override fun again(user: User) {
        isDrawn = false
        hanPokers.clear()
        // todo 验证
        getPlayer(user)?.reset()
    }

    override fun bao(user: User) {
        val player = getPlayer(user) ?: return
        player.state = PlayerState.BAO
        player.friendType = FriendType.BAO
        player.friendTypeTemp = FriendType.BAO
        val nextPlayer = player.nextPlayer() ?: return
        if (nextPlayer.state != PlayerState.BAO_PASS) {// 爆牌轮子还没轮完
            nextPlayer.state = PlayerState.FAN_BAO_TURN
            nextPlayer.friendType = FriendType.OTHER
            nextPlayer.friendTypeTemp = FriendType.OTHER
            return
        }
        // 爆牌轮子已经轮完。即最后一家爆牌
        room.players.forEach {
            it?.state = if (it?.user?.id == user.id) {
                PlayerState.PLAY_TURN
            } else {
                PlayerState.PLAYING
            }
        }
        onReady(if (isDrawn) BaoType.DRAW_BAO else BaoType.BAO)
    }

    override fun fanBao(user: User) {
        room.players.forEach {
            if (it?.user?.id == user.id) {
                it.state = PlayerState.PLAYING
                it.friendType = FriendType.FAN_BAO
                it.friendTypeTemp = FriendType.FAN_BAO
            } else if (it?.state == PlayerState.BAO) {
                it.state = PlayerState.PLAY_TURN
            } else {
                it?.reset()
            }
        }
        onReady(if (isDrawn) BaoType.DRAW_FAN_BAO else BaoType.FAN_BAO)
    }

    override fun baoPass(user: User) {
        val player = getPlayer(user) ?: return
        player.state = PlayerState.BAO_PASS
        val nextPlayer = player.nextPlayer() ?: return
        if (nextPlayer.state != PlayerState.BAO_PASS) {
            nextPlayer.state = PlayerState.BAO_TURN
            return
        }
        // 没有爆牌
        if (!isDrawn) {
            isDrawn = true
            room.players.forEach {
                it?.state = PlayerState.DRAWING
            }
        } else {
            val spade7Player = getSpade7Player()
            room.players.forEach {
                it?.state = if (it?.user?.id == spade7Player?.user?.id) {
                    PlayerState.FIND_FRIEND
                } else {
                    PlayerState.PLAYING
                }
            }
            onReady(BaoType.NONE)
        }
    }

    override fun fanBaoPass(user: User) {
        val player = getPlayer(user) ?: return
        player.state = PlayerState.FAN_BAO_PASS
        val nextPlayer = player.nextPlayer() ?: return
        if (nextPlayer.state != PlayerState.BAO_PASS && nextPlayer.state != PlayerState.BAO) {
            nextPlayer.state = PlayerState.FAN_BAO_TURN
            return
        }
        // 有爆牌，无反爆
        room.players.forEach {
            it?.state = if (it?.state == PlayerState.BAO) {
                PlayerState.PLAY_TURN
            } else {
                PlayerState.PLAYING
            }
        }
        onReady(if (isDrawn) BaoType.DRAW_BAO else BaoType.BAO)
    }

    override fun getAllFindFriendPokers(): List<Poker> {
        return hanPokers.toList()
    }

    override fun findFriend(user: User, id: Int) {
        val player = getPlayer(user) ?: return
        player.hanPoker = hanPokers.firstOrNull { it.id == id } ?: return
        player.state = PlayerState.PLAY_TURN_WIN
        room.players.forEach {
            it?.friendTypeTemp = if (it?.user?.id == user.id || it?.user?.id == player.hanPoker?.holderUserId) {
                FriendType.PARTY_A
            } else {
                FriendType.PARTY_B
            }
        }
    }

    override fun drawPlayed(user: User, ids: List<Int>) {
        val player = getPlayer(user) ?: return
        player.state = PlayerState.DRAW_PLAYED
        room.pokers.forEach {
            if (ids.contains(it.id)) {
                it.state = PokerState.DRAW_DECKS
            }
        }
        if (room.players.all { it?.state == PlayerState.DRAW_PLAYED }) {
            getSpade7Player()?.state = PlayerState.DRAW_TURN
            room.pokers.forEach {
                if (it.state == PokerState.DRAW_DECKS) {
                    it.state = PokerState.DRAW_WAIT
                }
            }
        }
    }

    override fun drawTake(user: User, ids: List<Int>) {
        val player = getPlayer(user) ?: return
        player.state = PlayerState.BAOING
        room.pokers.forEach {
            if (ids.contains(it.id)) {
                it.state = PokerState.NORMAL
                it.holderUserId = player.user.id
                hanPokers.remove(it)
            }
        }
        if (room.players.all { it?.state == PlayerState.BAOING }) {
            getSpade7Player()?.state = PlayerState.BAO_TURN
        } else {
            player.nextPlayer()?.state = PlayerState.DRAW_TURN
        }
    }

}